/*
 * Copyright (c) 2024 Black Sesame Technologies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "asf-tools/GeneralServiceGeneratorExtensions.h"
#include "FDModel/FDModelManager.h"
#include "FDModel/FDeployedProvider.h"
#include "asf-tools/FireAndForgetLimits.h"
#include "asf-tools/MsgType.h"
#include "capicxx-core-tools/FTypeGenerator.h"
#include "capicxx-core-tools/FrancaGeneratorExtensions.h"
#include "model/FFactory.h"
#include "model/FModelManager.h"
#include "someipTools/FrancaSomeIPGeneratorExtensions.h"
#include "someipTools/SomeipPropertyAccessor.h"
#include "utilities/string_utility.h"

namespace BstASF
{

std::string GeneralServiceGeneratorExtensions::getElementName(
    const std::shared_ptr<BstIdl::FModelElement> &fModelElement) const
{
    auto &ins = BstCommonAPI::FrancaGeneratorExtensions::getInstance();
    return ins.getElementName(fModelElement);
}

std::string GeneralServiceGeneratorExtensions::getInstanceName(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance) const
{
    if ((instance->getName().empty() || instance->getName() == ""))
        return "__Anonymous__";

    auto elements = split(instance->getName(), ".");
    for (auto &ele : elements)
    {
        ele = toFirstUpper(ele);
    }
    auto InstanceName = join(elements, "");
    return InstanceName;
}

std::list<std::string> GeneralServiceGeneratorExtensions::splitCamelCase(const std::string &str)
{
    std::list<uint32_t> pos;
    for (auto it = str.begin(); it != str.end(); it++)
    {
        if (((*it) - 'A') >= 0 && ('Z' - (*it)) >= 0)
        {
            pos.push_back(it - str.begin());
        }
    }
    std::list<std::string> words;
    uint32_t begin = pos.front();
    // if the first character is lowercase
    if (begin != 0)
    {
        words.push_back(str.substr(0, begin));
    }
    while (pos.size() > 1)
    {
        pos.pop_front();
        uint32_t end = pos.front();
        words.push_back(str.substr(begin, end - begin));
        begin = end;
    }
    if (pos.size() == 1)
        words.push_back(str.substr(begin, str.size() - begin));
    // the whole world is lowercase
    if (words.empty())
    {
        words.push_back(str);
    }
    return words;
}

std::string GeneralServiceGeneratorExtensions::getDefineName(
    const std::shared_ptr<BstIdl::FModelElement> &fModelElement)
{
    auto &ins = BstCommonAPI::FrancaGeneratorExtensions::getInstance();
    return ins.getDefineName(fModelElement);
}

std::string GeneralServiceGeneratorExtensions::getProjectDefineName(
    const std::shared_ptr<BstIdl::FModelElement> &fModelElement)
{
    auto words = splitCamelCase(getElementName(fModelElement));
    std::string defineName;
    defineName = join(words, "_");
    return defineName;
}
std::string GeneralServiceGeneratorExtensions::getProjectDefineName(
    const std::shared_ptr<BstIdl::FDExtensionElement> &fdExtensionElement)
{
    auto name = getInstanceName(fdExtensionElement);
    if (!name.compare("__Anonymous__"))
        return name;

    auto words = splitCamelCase(getInstanceName(fdExtensionElement));
    std::string defineName;
    defineName = join(words, "_");
    return defineName;
}

std::map<std::string, bool> GeneralServiceGeneratorExtensions::getMethodReplies(
    const std::shared_ptr<BstIdl::FMethod> &md) const
{
    if (m_allMethodRepliesMap.count(md))
        return m_allMethodRepliesMap.at(md);
    return std::map<std::string, bool>();
}

std::shared_ptr<BstCommonAPI::SomeipPropertyAccessor> GeneralServiceGeneratorExtensions::getSomeipAccessor(
    const std::shared_ptr<BstIdl::FTypeCollection> &tc) const
{
    if (m_someipInterfaceAccessor.count(tc))
        return m_someipInterfaceAccessor.at(tc);
    return nullptr;
}

std::string GeneralServiceGeneratorExtensions::generateASFLicenseHeader()
{
    auto &ins = BstCommonAPI::FrancaGeneratorExtensions::getInstance();
    auto &someipIns = BstCommonAPI::FrancaSomeIPGeneratorExtensions::getInstance();
    std::string header = R"(/*
 * This file was generated by the BST IDL Generator.
 * All manual modifications will be LOST by next generation.
 * Comaptible to org.genivi.commonapi.someip $CAPI_SOMEIP_VER
 * Compatible to org.genivi.commonapi.core $CAPI_VER
 * Compatible to org.franca.core $FRANCA_VER
 * Generator Version: fidl-generator $GEN_VER
 */
)";

    replace_one(header, "$CAPI_SOMEIP_VER", someipIns.getSomeIPVersion());
    replace_one(header, "$CAPI_VER", ins.getCoreVersion());
    replace_one(header, "$FRANCA_VER", ins.getFrancaVersion());
    replace_one(header, "$GEN_VER", COMMIT_HASH);
    return header;
}

std::string GeneralServiceGeneratorExtensions::getASFVersion()
{
    return " 4.1.0"; // focus
}

void GeneralServiceGeneratorExtensions::mergeDeployments(const std::shared_ptr<BstIdl::FDInterface> &_source,
                                                         const std::shared_ptr<BstIdl::FDInterface> &_target)
{
    BstCommonAPI::FrancaGeneratorExtensions::getInstance().mergeDeployments(_source, _target);
}

void GeneralServiceGeneratorExtensions::mergeDeployments(const std::shared_ptr<BstIdl::FDTypes> &_source,
                                                         const std::shared_ptr<BstIdl::FDTypes> &_target)
{
    BstCommonAPI::FrancaGeneratorExtensions::getInstance().mergeDeployments(_source, _target);
}
std::string GeneralServiceGeneratorExtensions::generateOverloadedStubSignatureWithNamespace(
    const std::shared_ptr<BstIdl::FMethod> &fMethod, const std::map<std::string, bool> &replies) const
{
    std::string signature = "const std::shared_ptr<CommonAPI::ClientId> _client";

    if (!isFireAndForgetMethod(fMethod))
    {
        for (const auto &it : replies)
        {
            if (it.second == true)
            {
                // replies containing error replies
                signature = signature + ", const CommonAPI::CallId_t _callId";
            }
        }
    }

    for (auto it : fMethod->getInArgs())
    {
        signature += ", " + getTypeName(it, fMethod, true) + " _" + getElementName(it);
    }
    auto inf = std::dynamic_pointer_cast<BstIdl::FInterface>(fMethod->getContainer());
    if (!inf)
        return std::string();
    auto ns = inf->getNameSpace() + "::" + inf->getName() + "StubDefault::";
    if (!isFireAndForgetMethod(fMethod))
    {
        for (const auto &entry : replies)
        {
            auto methodName = entry.first;
            auto isErrorReply = entry.second;
            signature += ", " + ns + methodName + "Reply_t";
            if (isErrorReply)
            {
                signature += " _" + methodName + "Reply";
            }
            else
            {
                signature += " _reply";
            }
        }
    }

    return signature;
}

std::string GeneralServiceGeneratorExtensions::generateOverloadedStubSignatureTypeWithNamespace(
    const std::shared_ptr<BstIdl::FMethod> &fMethod, const std::map<std::string, bool> &replies) const
{
    std::string signature = "const std::shared_ptr<CommonAPI::ClientId>";

    if (!isFireAndForgetMethod(fMethod))
    {
        for (const auto &it : replies)
        {
            if (it.second == true)
            {
                // replies containing error replies
                signature = signature + ", const CommonAPI::CallId_t _callId";
            }
        }
    }

    for (auto it : fMethod->getInArgs())
    {
        signature += ", " + getTypeName(it, fMethod, true);
    }
    auto inf = std::dynamic_pointer_cast<BstIdl::FInterface>(fMethod->getContainer());
    if (!inf)
        return std::string();
    auto ns = inf->getNameSpace() + "::" + inf->getName() + "StubDefault::";
    if (!isFireAndForgetMethod(fMethod))
    {
        for (const auto &entry : replies)
        {
            auto methodName = entry.first;
            auto isErrorReply = entry.second;
            signature += ", " + ns + methodName + "Reply_t";
        }
    }

    return signature;
}

std::string GeneralServiceGeneratorExtensions::generateOverloadedStubSignature(
    const std::shared_ptr<BstIdl::FMethod> &fMethod, const std::map<std::string, bool> &replies) const
{
    std::string signature = "const std::shared_ptr<CommonAPI::ClientId> _client";

    if (!isFireAndForgetMethod(fMethod))
    {
        for (const auto &it : replies)
        {
            if (it.second == true)
            {
                // replies containing error replies
                signature = signature + ", const CommonAPI::CallId_t _callId";
            }
        }
    }

    for (const auto &it : fMethod->getInArgs())
    {
        signature += ", " + getTypeName(it, fMethod, true) + " _" + getElementName(it);
    }

    if (!isFireAndForgetMethod(fMethod))
    {
        for (const auto &entry : replies)
        {
            auto methodName = entry.first;
            auto isErrorReply = entry.second;
            signature += ", " + methodName + "Reply_t";
            if (isErrorReply)
            {
                signature += " _" + methodName + "Reply";
            }
            else
            {
                signature += " _reply";
            }
        }
    }
    return signature;
}

// get paras in method
std::string GeneralServiceGeneratorExtensions::generateOverloadedStubParaNames(
    const std::shared_ptr<BstIdl::FMethod> &fMethod, const std::map<std::string, bool> &replies) const
{
    std::string paras = " _client";

    if (!isFireAndForgetMethod(fMethod))
    {
        for (const auto &it : replies)
        {
            if (it.second == true)
            {
                // replies containing error replies
                paras = paras + ", _callId";
            }
        }
    }

    for (const auto &it : fMethod->getInArgs())
    {
        paras += ", _" + getElementName(it);
    }
    if (!isFireAndForgetMethod(fMethod))
    {
        for (const auto &entry : replies)
        {
            auto isErrorReply = entry.second;
            if (isErrorReply)
            {
                paras += ", _Reply";
            }
            else
            {
                paras += ", _reply";
            }
        }
    }

    return paras;
}

bool GeneralServiceGeneratorExtensions::isErrorType(
    const std::shared_ptr<BstIdl::FBroadcast> &fBroadcast, const std::shared_ptr<BstIdl::FMethod> &fMethod,
    const std::shared_ptr<BstCommonAPI::CommonapiPropertyAccessor> &deploymentAccessor)
{
    auto &ins = BstCommonAPI::FrancaGeneratorExtensions::getInstance();
    return ins.isErrorType(fBroadcast, fMethod, deploymentAccessor);
}

std::string GeneralServiceGeneratorExtensions::getHeaderFile(
    const std::shared_ptr<BstIdl::FTypeCollection> &fTypeCollection)
{
    return BstCommonAPI::FrancaGeneratorExtensions::getInstance().getHeaderFile(fTypeCollection);
}

// new stubimpl
std::string GeneralServiceGeneratorExtensions::getStubImplHeaderFile(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    return getElementName(fInterface) + "StubImpl" + ".hpp";
}

std::string GeneralServiceGeneratorExtensions::getStubImplHeaderPath(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (isProjectMode())
        return "include/" + getStubImplHeaderFile(fInterface);
    return "/" + getStubImplHeaderFile(fInterface);
}

std::string GeneralServiceGeneratorExtensions::getStubImplSourceFile(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    return getElementName(fInterface) + "StubImpl" + ".cpp";
}

std::string GeneralServiceGeneratorExtensions::getStubImplSourcePath(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (isProjectMode())
        return "src/" + getStubImplSourceFile(fInterface);
    return "/" + getStubImplSourceFile(fInterface);
}
std::string GeneralServiceGeneratorExtensions::getStubImplHeaderFile(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    return getStubImplClassName(instance) + ".hpp";
}

std::string GeneralServiceGeneratorExtensions::getStubImplHeaderPath(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    if (isProjectMode())
        return "include/" + getStubImplHeaderFile(instance);
    return "/" + getStubImplHeaderFile(instance);
}

std::string GeneralServiceGeneratorExtensions::getStubImplSourceFile(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    return getStubImplClassName(instance) + ".cpp";
}

std::string GeneralServiceGeneratorExtensions::getStubImplSourcePath(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    if (isProjectMode())
        return "src/" + getStubImplSourceFile(instance);
    return "/" + getStubImplSourceFile(instance);
}

std::string GeneralServiceGeneratorExtensions::generateStubMethodDefine(
    const std::shared_ptr<BstIdl::FMethod> &fMethod, const std::map<std::string, bool> &replies,
    const std::string &serverName, const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    std::string define("");
    auto currInf = std::dynamic_pointer_cast<BstIdl::FInterface>(fMethod->getContainer());
    auto fInterface = std::dynamic_pointer_cast<BstIdl::FInterface>(instance->getTarget());
    if (fInterface == nullptr || getServer(fInterface).empty() || currInf == nullptr)
        return define;

    define += "\nvoid " + getStubImplClassName(instance) + "::" + getElementName(fMethod) + "(" +
              generateOverloadedStubSignatureWithNamespace(fMethod, replies) + ") \n{";

    auto name = fMethod->getName();
    if (currInf == fInterface && isRecordAndSimulateInterface(currInf) && contains(record_simulate_methods, name))
    {
        define += getRecordDefineInStubImpl(fMethod);
    }
    else
    {
        // if
        define += "\n\tauto msg = createRequestMessage(\"" + serverName + "\", __func__, " +
                  generateOverloadedStubParaNames(fMethod, replies) + ");";
        define += "\n\tmsg->setRecord(m_record);";
        define += "\n\tauto framework = AdvancedService::getInstance();";
        define += "\n\tstd::shared_ptr<TCAPIDriver> driver = "
                  "std::dynamic_pointer_cast<TCAPIDriver>(framework->getDriver(\"TCAPIDriver\"));";
        define += "\n\tif (driver)";
        define += "\n\t\tdriver->emitSignal(&TCAPIDriver::dataReceived, *msg);";
    }
    define += "\n}";
    return define;
}

// new logicDefault
std::string GeneralServiceGeneratorExtensions::getLogicDefaultHeaderFile(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    return getElementName(fInterface) + "ServerLogicDefault" + ".h";
}

std::string GeneralServiceGeneratorExtensions::getLogicDefaultHeaderPath(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (isProjectMode())
        return getLogicDefaultHeaderFile(fInterface);

    return getVersionPathPrefix(fInterface) +
           getDirectoryPath(std::dynamic_pointer_cast<BstIdl::FModel>(fInterface->getContainer())) + "/" +
           getLogicDefaultHeaderFile(fInterface);
}

std::string GeneralServiceGeneratorExtensions::getLogicDefaultSourceFile(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    return getElementName(fInterface) + "ServerLogicDefault" + ".cpp";
}

std::string GeneralServiceGeneratorExtensions::getLogicDefaultSourcePath(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (isProjectMode())
        return getLogicDefaultSourceFile(fInterface);

    return getVersionPathPrefix(fInterface) +
           getDirectoryPath(std::dynamic_pointer_cast<BstIdl::FModel>(fInterface->getContainer())) + "/" +
           getLogicDefaultSourceFile(fInterface);
}

// logic
std::string GeneralServiceGeneratorExtensions::getLogicHeaderFile(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    return getElementName(fInterface) + "ServerLogic" + ".h";
}

std::string GeneralServiceGeneratorExtensions::getLogicHeaderPath(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (isProjectMode())
        return "include/" + getLogicHeaderFile(fInterface);
    return "/" + getLogicHeaderFile(fInterface);
}

std::string GeneralServiceGeneratorExtensions::getLogicSourceFile(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    return getElementName(fInterface) + "ServerLogic" + ".cpp";
}

std::string GeneralServiceGeneratorExtensions::getLogicSourcePath(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (isProjectMode())
        return "src/" + getLogicSourceFile(fInterface);
    return "/" + getLogicSourceFile(fInterface);
}

// config
std::string GeneralServiceGeneratorExtensions::getCapiConfigHeaderFile()
{
    return "capiconfig.h";
}

std::string GeneralServiceGeneratorExtensions::getCapiConfigHeaderPath()
{
    if (isProjectMode())
        return "src-gen/" + getCapiConfigHeaderFile();
    return "/" + getCapiConfigHeaderFile();
}

std::string GeneralServiceGeneratorExtensions::getCapiConfigSourceFile()
{
    return "capiconfig.cpp";
}

std::string GeneralServiceGeneratorExtensions::getCapiConfigSourcePath()
{
    if (isProjectMode())
        return "src-gen/" + getCapiConfigSourceFile();
    return "/" + getCapiConfigSourceFile();
}
// main
std::string GeneralServiceGeneratorExtensions::getMainSourceFile()
{
    return "main.cpp";
}

std::string GeneralServiceGeneratorExtensions::getMainSourcePath()
{
    if (isProjectMode())
        return "src/" + getMainSourceFile();
    return "/" + getMainSourceFile();
}
// typeconversion : only used with Record and simulate functions at project mode.
std::string GeneralServiceGeneratorExtensions::getTypeConversionHeaderFile()
{
    return "typeconversion.h";
}

std::string GeneralServiceGeneratorExtensions::getTypeConversionPath()
{
    if (isProjectMode())
        return "include/" + getTypeConversionHeaderFile();
    return "/" + getTypeConversionHeaderFile();
}
// class name
std::string GeneralServiceGeneratorExtensions::getStubImplClassName(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    return getElementName(fInterface) + "StubImpl";
}

std::string GeneralServiceGeneratorExtensions::getLogicDefaultClassName(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    return getElementName(fInterface) + "ServerLogicDefault";
}

std::string GeneralServiceGeneratorExtensions::getStubDefaultClassName(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    return getElementName(fInterface) + "StubDefault";
}

std::string GeneralServiceGeneratorExtensions::getLogicClassName(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    return getElementName(fInterface) + "ServerLogic";
}

std::string GeneralServiceGeneratorExtensions::getLogicClassName(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    auto userLogicName = getUserLogicName(instance);
    if (!userLogicName.empty())
        return userLogicName;
    auto inf = std::dynamic_pointer_cast<BstIdl::FInterface>(instance->getTarget());
    if (getServer(inf).size() > 1)
        return getInstanceName(instance) + "ServerLogic";
    else
        return getLogicClassName(inf);
}

std::string GeneralServiceGeneratorExtensions::getStubImplClassName(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    auto inf = std::dynamic_pointer_cast<BstIdl::FInterface>(instance->getTarget());
    if (getServer(inf).size() > 1)
        return getInstanceName(instance) + "StubImpl";
    else
        return getStubImplClassName(inf);
}

std::string GeneralServiceGeneratorExtensions::getLogicHeaderFile(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    auto userLogicHeaderPath = getUserLogicHeaderPath(instance);
    return userLogicHeaderPath.empty() ? getLogicClassName(instance) + ".h" : userLogicHeaderPath;
}

std::string GeneralServiceGeneratorExtensions::getLogicHeaderPath(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    if (isProjectMode())
        return "include/" + getLogicHeaderFile(instance);
    return "/" + getLogicHeaderFile(instance);
}

std::string GeneralServiceGeneratorExtensions::getLogicSourceFile(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    return getLogicClassName(instance) + ".cpp";
}

std::string GeneralServiceGeneratorExtensions::getLogicSourcePath(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    if (isProjectMode())
        return "src/" + getLogicSourceFile(instance);
    return "/" + getLogicSourceFile(instance);
}

std::string GeneralServiceGeneratorExtensions::getConfigClassName()
{
    return "capiconfig";
}

std::string GeneralServiceGeneratorExtensions::getStubDefaultHeaderPath(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    auto &ins = BstCommonAPI::FrancaGeneratorExtensions::getInstance();
    return ins.getStubDefaultHeaderPath(fInterface);
}

std::string GeneralServiceGeneratorExtensions::getVersionPathPrefix(const std::shared_ptr<BstIdl::FTypeCollection> &_tc)
{
    auto &ins = BstCommonAPI::FrancaGeneratorExtensions::getInstance();
    return ins.getVersionPathPrefix(_tc);
}

std::string GeneralServiceGeneratorExtensions::getDirectoryPath(const std::shared_ptr<BstIdl::FModel> &fModel)
{
    auto &ins = BstCommonAPI::FrancaGeneratorExtensions::getInstance();
    return ins.getDirectoryPath(fModel);
}

std::string GeneralServiceGeneratorExtensions::getStubDefaultHeaderFile(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    auto &ins = BstCommonAPI::FrancaGeneratorExtensions::getInstance();
    return ins.getStubDefaultHeaderFile(fInterface);
}

std::string GeneralServiceGeneratorExtensions::getStubSourceFile(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    auto &ins = BstCommonAPI::FrancaGeneratorExtensions::getInstance();
    return ins.getStubSourceFile(fInterface);
}

std::string GeneralServiceGeneratorExtensions::getStubHeaderFile(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    auto &ins = BstCommonAPI::FrancaGeneratorExtensions::getInstance();
    return ins.getStubHeaderFile(fInterface);
}

// get auto-startup config file & path
std::string GeneralServiceGeneratorExtensions::getStarUpConfigJsonFile(
    const std::shared_ptr<BstIdl::FDExtensionRoot> &provider)
{
    if (!provider)
        return std::string();
    return toLower(m_accessor->getProcessName(provider)) + "_config.json";
}

std::string GeneralServiceGeneratorExtensions::getStarUpSystemdConfigFile(
    const std::shared_ptr<BstIdl::FDExtensionRoot> &provider)
{
    if (!provider)
        return std::string();
    return toLower(m_accessor->getProcessName(provider)) + "-service.service";
}

std::string GeneralServiceGeneratorExtensions::getStarUpSLMConfigFile(
    const std::shared_ptr<BstIdl::FDExtensionRoot> &provider)
{
    if (!provider)
        return std::string();
    return toLower(m_accessor->getProcessName(provider)) + "_config.xml";
}

std::string GeneralServiceGeneratorExtensions::generateNamespaceBeginDeclaration(
    const std::shared_ptr<BstIdl::FModel> &model)
{
    auto &ins = BstCommonAPI::FrancaGeneratorExtensions::getInstance();
    return ins.generateNamespaceBeginDeclaration(model);
}

void GeneralServiceGeneratorExtensions::clearServer()
{
    m_servers.clear();
}

const bool GeneralServiceGeneratorExtensions::isEmptyServer() const
{
    return m_servers.empty();
}

void GeneralServiceGeneratorExtensions::addServer(const std::shared_ptr<BstIdl::FInterface> &fInterface,
                                                  const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    m_servers.emplace(fInterface, instance);
}

bool GeneralServiceGeneratorExtensions::isServer(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (!fInterface)
        return false;
    auto it = m_servers.find(fInterface);
    if (it == m_servers.end())
        return false;
    return true;
}

std::list<std::shared_ptr<BstIdl::FDExtensionElement>> GeneralServiceGeneratorExtensions::getServer(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (!isServer(fInterface))
        return std::list<std::shared_ptr<BstIdl::FDExtensionElement>>();
    std::list<std::shared_ptr<BstIdl::FDExtensionElement>> tmp;
    auto begin = m_servers.lower_bound(fInterface);
    for (; begin != m_servers.upper_bound(fInterface); ++begin)
    {
        if (isServerTypeInstance(begin->second))
            addListItem(tmp, begin->second);
    }
    return tmp;
}

std::list<std::shared_ptr<BstIdl::FInterface>> GeneralServiceGeneratorExtensions::getServerInterfaces() const
{
    std::list<std::shared_ptr<BstIdl::FInterface>> infs;
    for (const auto &pairs : m_servers)
    {
        addListItem(infs, pairs.first);
    }
    return infs;
}
std::list<std::shared_ptr<BstIdl::FDExtensionElement>> GeneralServiceGeneratorExtensions::getServerInstances() const
{
    std::list<std::shared_ptr<BstIdl::FDExtensionElement>> instances;
    for (const auto &pairs : m_servers)
    {
        if (isServerTypeInstance(pairs.second))
            addListItem(instances, pairs.second);
    }
    return instances;
}

std::list<std::shared_ptr<BstIdl::FDExtensionElement>> GeneralServiceGeneratorExtensions::getClientInstances() const
{
    std::list<std::shared_ptr<BstIdl::FDExtensionElement>> instances;
    for (const auto &pairs : m_servers)
        if (isClientTypeInstance(pairs.second))
            addListItem(instances, pairs.second);
    return instances;
}

std::string GeneralServiceGeneratorExtensions::getDomainName(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    std::string domain_name("");
    if (!instance)
    {
        std::cerr << "Error : The instance parameter of function getDomainName is nullptr !" << std::endl;
        return domain_name;
    }
    auto res = getSomeIPDomain(instance);
    return res;
}

std::string GeneralServiceGeneratorExtensions::getInstanceID(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    std::string instance_id("");
    if (!instance)
    {
        std::cerr << "Error : The instance parameter of function getInstanceID is nullptr !" << std::endl;
        return instance_id;
    }
    return getSomeIPInstanceId(instance);
}

std::string GeneralServiceGeneratorExtensions::getSomeIPDomain(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    if (!instance || !instance->getTarget())
        return nullptr;
    auto &mgr = BstIdl::FDModelManager::getInstance();
    if (auto someipInstance =
            mgr.findInstance("org.genivi.commonapi.someip.deployment", instance->getTarget()->getName()))
    {
        return m_someipProviderAccesssor->getDomain(someipInstance);
    }
    return std::string();
}

std::string GeneralServiceGeneratorExtensions::getSomeIPInstanceId(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    if (!instance || !instance->getTarget())
        return nullptr;
    auto &mgr = BstIdl::FDModelManager::getInstance();
    if (auto someipInstance =
            mgr.findInstance("org.genivi.commonapi.someip.deployment", instance->getTarget()->getName()))
    {
        return m_someipProviderAccesssor->getInstanceId(someipInstance);
    }
    return std::string();
}

std::string GeneralServiceGeneratorExtensions::getServerName(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    if (!instance)
        return std::string("");
    return getDomainName(instance) + ":" + getInstanceID(instance);
}

std::string GeneralServiceGeneratorExtensions::getSlotName(const std::string &msgType,
                                                           const std::shared_ptr<BstIdl::FModelElement> &obj,
                                                           const std::shared_ptr<BstIdl::FInterface> fInterface)
{
    auto msg = MsgType::getByName(msgType);
    if (fInterface == nullptr || !msg)
        return std::string("");

    auto slotName = msg->getLiteral();
    std::string tmp("_" + getElementName(fInterface) + "_" + getElementName(obj));
    switch (msg->getValue())
    {
    case MsgType::Method:
        slotName += tmp;
        break;
    case MsgType::Attribute:
        slotName += tmp;
        break;
    case MsgType::Broadcast:
        slotName += tmp;
        break;
    case MsgType::AvailStatus:
        slotName += "_" + getElementName(obj);
        break;
    case MsgType::Reply:
    default:
        return std::string();
    }
    return slotName;
}

void GeneralServiceGeneratorExtensions::getSlotList(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (!fInterface || !isServer(fInterface))
        return;

    std::list<std::string> tmp;
    auto baseInterfaces = BstIdl::FModelManager::getInstance().getBaseInterfaces(fInterface);
    for (const auto &inf : baseInterfaces)
    {
        for (const auto &md : inf->getMethods())
        {
            if (isRecordAndSimulateInterface(inf) && contains(record_simulate_methods, md->getName()))
                continue;
            auto selector = md->getSelector();
            if (!selector.empty())
                selector = "WithOverrideSelector" + selector;
            tmp.emplace_back(getSlotName("Method", md, fInterface) + selector);
        }
    }
    m_slotsMap.emplace(fInterface, tmp);
}

std::string GeneralServiceGeneratorExtensions::getSlots(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (!fInterface || !isServer(fInterface) || !m_slotsMap.count(fInterface))
        return std::string("");
    // SLOT(slotname)
    auto slotList = m_slotsMap.at(fInterface);
    std::string slots("");
    for (const auto &slotName : slotList)
    {
        slots += "\n\tSLOT(" + slotName + ")";
    }
    return slots;
}

// logicDefault
std::string GeneralServiceGeneratorExtensions::getDeclSlots(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (!fInterface || !isServer(fInterface) || !m_slotsMap.count(fInterface))
        return std::string();
    // SLOT(logicDefaultName, slotname)
    auto lDName = getLogicDefaultClassName(fInterface);
    auto slotList = m_slotsMap.at(fInterface);
    std::string declSlots("");
    for (const auto &slotName : slotList)
    {
        declSlots += "\n\tDECL_SLOT(" + lDName + ", " + slotName + ")";
    }
    return declSlots;
}
// func
std::string GeneralServiceGeneratorExtensions::getSlotFunctions(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (!fInterface || !isServer(fInterface) || !m_slotsMap.count(fInterface))
        return std::string();
    auto lDName = getLogicDefaultClassName(fInterface);
    auto slotList = m_slotsMap.at(fInterface);
    auto inf_name = getElementName(fInterface);
    std::string functions("");
    for (const auto &slotName : slotList)
    {
        if (contains(slotName, "TCAPIMsg_AvailStatus"))
        {
            functions.append("\nvoid " + lDName + "::" + slotName + "(TParam& param)" + "\n{");
            functions.append("\n\tTCAPIMsgAvailStatImp* msg = dynamic_cast<TCAPIMsgAvailStatImp*>(&param);");
            functions.append("\n\tif (!msg)");
            functions.append("\n\t\treturn;");
            functions.append("\n\tif (msg->isAvailable())");
            functions.append("\n\t{");
            functions.append("\n\t\tauto framework = AdvancedService::getInstance();");
            functions.append("\n\t\tstd::shared_ptr<TCAPIDriver> capidrv = "
                             "std::dynamic_pointer_cast<TCAPIDriver>(framework->getDriver(\"TCAPIDriver\"));");
            functions.append("\n\t\tauto config = std::dynamic_pointer_cast<CAPIConfig>(capidrv->getConfig());");
            functions.append("\n\t\tm_service = config->get");
            functions.append(inf_name + "Service();");
            functions.append("\n\t\tsetAvailable(true);");
            functions.append("\n\t}");
            functions.append("\n\telse");
            functions.append("\n\t{");
            functions.append("\n\t\tsetAvailable(false);");
            functions.append("\n\t}");
            functions.append("\n}\n");
        }
        else
        {
            functions.append("\nvoid " + lDName + "::" + slotName + "(TParam& param)" + "\n{");
            functions.append(getSlotMethodName(fInterface, slotName));
            functions.append("\n}\n");
        }
    }
    return functions;
}

std::string GeneralServiceGeneratorExtensions::getConnectSlots(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (!fInterface || !isServer(fInterface) || !m_slotsMap.count(fInterface))
        return std::string("");
    std::string connect("");
    auto logic = toLower(getElementName(fInterface)) + "logic";
    auto slotList = m_slotsMap.at(fInterface);
    int i = 0;
    for (const auto &msg : slotList)
    {
        connect += "CONNECT(tdispatcher,\"output" + std::to_string(i) + "\"," + logic + ",\"" + msg + "\");";
        ++i;
    }
    connect += "CONNECT(" + logic + ",\"output\",tcapidriver,\"sendData\");";

    return connect;
}
std::list<std::string> GeneralServiceGeneratorExtensions::getSlotInMap(
    const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (!fInterface || !isServer(fInterface) || !m_slotsMap.count(fInterface))
        return std::list<std::string>();
    return m_slotsMap.at(fInterface);
}

std::string GeneralServiceGeneratorExtensions::TransToOverrideDeclStr(const std::string &_decl)
{
    std::string override_decl(_decl);
    return replace_one(override_decl, ";", " override;");;
}

std::string GeneralServiceGeneratorExtensions::getMethodDecl(const std::shared_ptr<BstIdl::FMethod> &md)
{
    std::string decl("virtual void ");
    decl += getElementName(md) + "(";
    std::map<std::string, bool> replies = getMethodReplies(md);
    if (!replies.empty())
    {
        decl += generateOverloadedStubSignatureWithNamespace(md, replies) + ");";
    }
    else
        decl += "const std::shared_ptr<CommonAPI::ClientId> _client);";
    return decl;
}

std::string GeneralServiceGeneratorExtensions::getMethodSeletcorFuncPtrDecl(const std::shared_ptr<BstIdl::FMethod> &md)
{
    std::string decl("void (");
    std::string space = getLogicDefaultClassName(std::dynamic_pointer_cast<BstIdl::FInterface>(md->getContainer()));
    auto name = getElementName(md);
    decl.append(space + "::*" + name + md->getSelector() + "Func)" + "(");
    std::map<std::string, bool> replies = getMethodReplies(md);
    if (!replies.empty())
    {
        decl += generateOverloadedStubSignatureTypeWithNamespace(md, replies) + ")";
    }
    else
        decl += "const std::shared_ptr<CommonAPI::ClientId>)";
    decl += " = &" + space + "::" + getElementName(md) + ";";
    return decl;
}

std::string GeneralServiceGeneratorExtensions::getMethodDefine(const std::shared_ptr<BstIdl::FMethod> &md,
                                                               const std::string &class_name)
{
    std::string define("");
    define += "\nvoid " + getElementName(md) + "(";
    std::string space = getLogicDefaultClassName(std::dynamic_pointer_cast<BstIdl::FInterface>(md->getContainer()));
    define.insert(6, class_name + "::");
    std::map<std::string, bool> replies = getMethodReplies(md);
    if (!replies.empty())
    {
        define += generateOverloadedStubSignatureWithNamespace(md, replies) + ")";
    }
    else
        define += "const std::shared_ptr<CommonAPI::ClientId> _client)";
    //{}
    define += "\n{";
    auto classname = std::string("ServerLogicDefault ");
    define += "\n\t// LOG_INFO(\"Enter " +
              getElementName(std::dynamic_pointer_cast<BstIdl::FModelElement>(md->getContainer())) + classname +
              getElementName(md) + " \");";
    define += "\n\t// TODO: Add the stub processing logic here.";
    define += "\n}";
    return define;
}

// logic
std::string GeneralServiceGeneratorExtensions::getLogicMethodDefine(const std::shared_ptr<BstIdl::FMethod> &md,
                                                                    const std::string &class_name)
{
    std::string define("");
    define += "\nvoid " + getElementName(md) + "(";
    std::string space = getLogicClassName(std::dynamic_pointer_cast<BstIdl::FInterface>(md->getContainer())) + "::";
    define.insert(6, class_name + "::");
    std::map<std::string, bool> replies = getMethodReplies(md);
    if (!replies.empty())
    {
        define += generateOverloadedStubSignatureWithNamespace(md, replies) + ")";
    }
    else
        define += "const std::shared_ptr<CommonAPI::ClientId> _client)";

    std::list<std::string> inArgs_names;
    for (auto it : md->getInArgs())
    {
        inArgs_names.push_back("_" + getElementName(it));
    }
    define += "\n{";
    auto classname = std::string("ServerLogic ");
    define += "\n\t// TODO: Add the stub processing logic here.";
    define += "\n\tLOG_INFO(\"Enter " +
              getElementName(std::dynamic_pointer_cast<BstIdl::FModelElement>(md->getContainer())) + classname +
              getElementName(md) + "\");";
    define += "\n}";
    return define;
}
// broadcast
std::string GeneralServiceGeneratorExtensions::getBroadcastDecl(const std::shared_ptr<BstIdl::FBroadcast> &bc)
{
    if (!bc)
        return std::string();
    std::string tmp(getElementName(bc));
    auto it = tmp.begin();
    *it = std::toupper(*it);

    auto decl = "virtual void fire" + tmp + "Event(";
    for (const auto &arg : bc->getOutArgs())
    {
        decl.append("const " + getTypeName(arg, bc, true) + "& _" + getElementName(arg) + ", ");
    }
    if (bc->isSelective())
        decl.append("const std::shared_ptr<CommonAPI::ClientIdList> _receivers = nullptr);");
    else
    {
        decl.erase(decl.find_last_of(","), 2);
        decl.append(");");
    }

    return decl;
}

std::string GeneralServiceGeneratorExtensions::getBroadcastDefine(const std::shared_ptr<BstIdl::FBroadcast> &bc,
                                                                  const std::string &class_name)
{
    if (!bc)
        return std::string();
    auto decl = getBroadcastDecl(bc);
    if (bc->isSelective())
        decl = replace_one(decl, " = nullptr);", ")");
    else
        decl.pop_back();
    auto define = "\n" + decl;
    define = define.substr(9);
    std::string space;

    define.insert(5, class_name + "::");
    define.append("\n{\n\tif (!m_service.expired())\n\t\t(m_service.lock())->" + getLogicClassFireBroadcastName(bc));
    // argList
    std::string argList("");
    for (const auto &arg : bc->getOutArgs())
    {
        argList.append("_" + getElementName(arg) + ", ");
    }
    if (bc->isSelective())
        argList.append("_receivers");
    else
        argList.erase(argList.find_last_of(","), 2);
    define.append("(" + argList + ");\n}");
    return define;
}

std::string GeneralServiceGeneratorExtensions::getLogicClassFireBroadcastName(
    const std::shared_ptr<BstIdl::FBroadcast> &fBroadcast)
{
    std::string str = toFirstUpper(getElementName(fBroadcast));
    fBroadcast->isSelective() ? str = "fire" + str + "Selective" : str = "fire" + str + "Event";
    return str;
}

// generate attr
std::string GeneralServiceGeneratorExtensions::getSetMethodDeclStr(const std::shared_ptr<BstIdl::FAttribute> &attr)
{
    std::string tmp(getElementName(attr));
    auto it = tmp.begin();
    *it = std::toupper(*it);
    auto container = std::dynamic_pointer_cast<BstIdl::FModelElement>(attr->getContainer());
    auto typeName = getTypeName(attr, container, true);
    std::string decl("virtual void");
    decl.append(" set" + tmp + "Attribute(" + "const " + typeName + "& _value);");
    return decl;
}

std::string GeneralServiceGeneratorExtensions::getSetMethodDefineStr(const std::shared_ptr<BstIdl::FAttribute> &attr,
                                                                     const std::string &class_name)
{
    std::string define("\n" + getSetMethodDeclStr(attr));
    define.pop_back();
    define = define.substr(9);
    auto container = std::dynamic_pointer_cast<BstIdl::FModelElement>(attr->getContainer());
    auto pos = 5;
    std::string space;

    define.insert(pos, class_name + "::");
    //{}
    std::string tmp(getElementName(attr));
    auto it = tmp.begin();
    *it = std::toupper(*it);
    define.append("\n{\n\tif (!m_service.expired())\n\t\t(m_service.lock())->set" + tmp + "Attribute(_value);\n}");
    return define;
}

std::string GeneralServiceGeneratorExtensions::getGetMethodDeclStr(const std::shared_ptr<BstIdl::FAttribute> &attr)
{
    std::string tmp(getElementName(attr));
    auto it = tmp.begin();
    *it = std::toupper(*it);
    auto container = std::dynamic_pointer_cast<BstIdl::FModelElement>(attr->getContainer());
    auto typeName = getTypeName(attr, container, true);
    std::string decl = "virtual " + typeName + " get" + tmp + "Attribute();";
    return decl;
}

std::string GeneralServiceGeneratorExtensions::getGetMethodDefineStr(const std::shared_ptr<BstIdl::FAttribute> &attr,
                                                                     const std::string &class_name)
{
    std::string define("\n" + getGetMethodDeclStr(attr));
    define.pop_back();
    define = define.substr(9);
    auto container = std::dynamic_pointer_cast<BstIdl::FModelElement>(attr->getContainer());
    auto pos = getTypeName(attr, container, true).size() + 1;
    std::string space;

    define.insert(pos, class_name + "::");
    //{}
    std::string tmp(getElementName(attr));
    auto it = tmp.begin();
    *it = std::toupper(*it);
    define.append("\n{\n\tif (!m_service.expired())\n\t\treturn (m_service.lock())->get" + tmp + "Attribute();");
    auto typeName = getTypeName(attr, container, true);
    define.append("\n\telse\n\t\treturn " + typeName);
    define.append("();\n}");
    return define;
}

std::string GeneralServiceGeneratorExtensions::getTypeName(const std::shared_ptr<BstIdl::FTypedElement> &_element,
                                                           const std::shared_ptr<BstIdl::FModelElement> &_source,
                                                           const bool _isOther) const
{
    auto &ins = BstCommonAPI::FrancaGeneratorExtensions::getInstance();
    return ins.getTypeName(_element, _source, _isOther);
}

std::string GeneralServiceGeneratorExtensions::getType(const std::string &slot)
{
    auto tmp = slot;
    remove_all(tmp, "on_TCAPIMsg_");
    auto pos = tmp.find_first_of("_");
    tmp = tmp.substr(0, pos);
    if (!MsgType::getByName(tmp))
        return std::string("");
    return tmp;
}

std::string GeneralServiceGeneratorExtensions::getFullName(const std::shared_ptr<BstIdl::FObject> &_me)
{
    return BstCommonAPI::FrancaGeneratorExtensions::getInstance().getFullName(_me);
}
std::string GeneralServiceGeneratorExtensions::getElementName(
    const std::shared_ptr<BstIdl::FModelElement> &fModelElement)
{
    return BstCommonAPI::FrancaGeneratorExtensions::getInstance().getElementName(fModelElement);
}
std::string GeneralServiceGeneratorExtensions::getSlotMethodName(const std::shared_ptr<BstIdl::FInterface> fInterface,
                                                                 const std::string &slot)
{
    std::string mdName(getType(slot));
    auto slotType = MsgType::getByName(mdName);
    if (!slotType)
    {
        std::cerr << "wrong slot :" << slot << std::endl;
        return std::string("");
    }
    auto literal = slotType->getLiteral();
    auto name = slot.substr(literal.size() + getElementName(fInterface).size() + 2);
    // record & simulate
    auto lDName = getLogicDefaultClassName(fInterface);
    if (isRecordAndSimulateInterface(fInterface) && contains(record_simulate_methods, name))
        return std::string("\n\thandleMethodMessage(*this,&" + lDName + "::" + name + " ,*msg);");

    auto &mgr = BstIdl::FModelManager::getInstance();
    auto md_full_name = name;
    auto pos = name.find("WithOverrideSelector");
    if (pos != std::string::npos)
    {
        md_full_name = name.substr(0, pos) + ":" + name.substr(pos + 20);
        name = name.substr(0, pos) + name.substr(pos + 20);
    }
    auto method = mgr.findFMethod(fInterface->getFQN() + "." + md_full_name);
    switch (MsgType::getByName(mdName)->getValue())
    {
    case 0: // method
        if (method->getSelector().empty() && (containsNumByName(fInterface->getMethods(), method) <= 1))
        {
            return std::string("\n\thandleMethodMessage(&" + lDName + "::" + name + ", &param);");
        }
        else
        {
            return std::string("\n\thandleMethodMessage(" + lDName + "::" + name + "Func, &param);");
        }
    case 1: // bd
        return std::string("\n\thandleBroadcastMessage(*this,&" + lDName + "::" + "on" + toFirstUpper(name) + "Fired" +
                           " ,*msg);");
    case 2: // attr
        return std::string("\n\thandleAttrMessage(*this,&" + lDName + "::" + "on" + toFirstUpper(name) +
                           "AttributeChanged" + " ,*msg);");
    case 3: // reply
        return std::string("\n\thandleMethodMessage(*this,&" + lDName + "::" + "on" + toFirstUpper(name) + "Reply" +
                           " ,*msg);");
    default:
        return std::string("");
    }
    return std::string("");
}

// record & simulate
bool GeneralServiceGeneratorExtensions::isRecordAndSimulateInterface(
    const std::shared_ptr<BstIdl::FInterface> &fInterface) const
{
    if (fInterface == nullptr)
        return false;
    return contains(m_rsInterfaces, fInterface);
}

void GeneralServiceGeneratorExtensions::addRecordAndSimulateInterface(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    auto fInterface = std::dynamic_pointer_cast<BstIdl::FInterface>(instance->getTarget());
    if (fInterface == nullptr || contains(m_rsInterfaces, fInterface))
        return;
    if (hasRecordMethod(fInterface) && hasRecordFDMethod(instance))
        addListItem(m_rsInterfaces, fInterface);
}

bool GeneralServiceGeneratorExtensions::hasRecordMethod(const std::shared_ptr<BstIdl::FInterface> &fInterface)
{
    if (fInterface == nullptr)
        return false;

    std::list<std::shared_ptr<BstIdl::FMethod>> methods;
    for (const auto &md : fInterface->getMethods())
    {
        if (md != nullptr)
            addListItem(methods, md);
    }

    for (const auto &name : record_simulate_methods)
    {
        auto iter =
            std::find_if(methods.cbegin(), methods.cend(), [&name](auto item) { return item->getName() == name; });
        if (iter != methods.cend() && isCorrectRecordMethod(*iter))
            continue;
        else
            return false;
    }
    return true;
}

bool GeneralServiceGeneratorExtensions::hasRecordFDMethod(const std::shared_ptr<BstIdl::FDExtensionElement> &instance)
{
    auto fdInterface = BstIdl::FDModelManager::getInstance().findInterfaceDeployment(
        "org.genivi.commonapi.someip.deployment", std::dynamic_pointer_cast<BstIdl::FInterface>(instance->getTarget()));
    ;
    if (fdInterface == nullptr)
    {
        std::cerr << "undefined \"org.genivi.commonapi.someip.deployment\" depl to interface named : "
                  << instance->getTarget()->getFQN();
        return false;
    }
    std::list<std::shared_ptr<BstIdl::FDMethod>> methods;
    for (const auto &md : fdInterface->getMethods())
    {
        if (md != nullptr)
            addListItem(methods, md);
    }

    for (const auto &name : record_simulate_methods)
    {
        auto iter = std::find_if(methods.cbegin(), methods.cend(), [&name](auto item) {
            std::string md_name(item->getName());
            auto pos = md_name.find_last_of(".");
            if (pos != std::string::npos)
                md_name = md_name.substr(pos + 1);
            return md_name == name;
        });

        if (iter != methods.cend() && isCorrectRecordFDMethod(*iter))
            continue;
        else
            return false;
    }
    return true;
}

const bool GeneralServiceGeneratorExtensions::isCorrectRecordMethod(const std::shared_ptr<BstIdl::FMethod> &fMethod)
{
    auto name = fMethod->getName();
    if (!contains(record_simulate_methods, name))
        return false;

    bool isCorrect = false;
    if (name == "startRecord" || name == "readRecord")
    {
        if (fMethod->getErrorType() == nullptr && fMethod->getInArgs().size() == 1 && fMethod->getOutArgs().empty() &&
            !isFireAndForgetMethod(fMethod))
        {
            const auto arg = fMethod->getInArgs().front();
            auto type = arg->getType()->getPredefined();
            auto typeDerived = arg->getType()->getDerived();
            auto typeInterval = arg->getType()->getInterval();
            if (arg->getName() == "path" && type != nullptr && type->getName() == "String" && typeDerived == nullptr &&
                typeInterval == nullptr)
            {
                isCorrect = true;
            }
        }
    }
    else if (name == "stopRecord")
    {
        if (fMethod->getErrorType() == nullptr && fMethod->getInArgs().empty() && fMethod->getOutArgs().empty() &&
            !isFireAndForgetMethod(fMethod))
        {
            isCorrect = true;
        }
    }

    return isCorrect;
}

const bool GeneralServiceGeneratorExtensions::isCorrectRecordFDMethod(const std::shared_ptr<BstIdl::FDMethod> &fdMethod)
{
    auto name = getFDMethodName(fdMethod);
    if (!contains(record_simulate_methods, name))
        return false;

    bool isCorrect = false;
    auto someipAccessor =
        getSomeipAccessor(std::dynamic_pointer_cast<BstIdl::FTypeCollection>(fdMethod->getTarget()->getContainer()));
    if (name == "startRecord" || name == "readRecord")
    {
        auto in_args = fdMethod->getInArguments();
        auto out_args = fdMethod->getOutArguments();
        if (in_args != nullptr && in_args->getArguments().size() == 1 && out_args != nullptr &&
            out_args->getArguments().size() == 0)
        {
            if (fdMethod->getProperties().size() == 2 &&
                someipAccessor->getSomeIpMethodID(fdMethod->getTarget()) != -1)
            {
                isCorrect = true;
            }
        }
    }
    else
    {
        auto in_args = fdMethod->getInArguments();
        auto out_args = fdMethod->getOutArguments();
        if (in_args != nullptr && in_args->getArguments().size() == 0 && out_args != nullptr &&
            out_args->getArguments().size() == 0)
        {
            if (fdMethod->getProperties().size() == 2 &&
                someipAccessor->getSomeIpMethodID(fdMethod->getTarget()) != -1)
            {
                isCorrect = true;
            }
        }
    }
    return isCorrect;
}

const std::string GeneralServiceGeneratorExtensions::getFDMethodName(const std::shared_ptr<BstIdl::FDMethod> &fdMethod)
{
    std::string md_name(fdMethod->getName());
    auto pos = md_name.find_last_of(".");
    if (pos != std::string::npos)
        md_name = md_name.substr(pos + 1);
    return md_name;
}

std::shared_ptr<BstIdl::FDInterface> GeneralServiceGeneratorExtensions::getSomeIpFDInterface(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance) const
{
    auto fdmodel = std::dynamic_pointer_cast<BstIdl::FDModel>(instance->getContainer()->getContainer());
    auto fdInterface =
        fdmodel->getInterfaceDeployment("org.genivi.commonapi.someip.deployment", instance->getTarget()->getName());

    if (fdInterface == nullptr || fdInterface->getTarget() != instance->getTarget())
    {
        auto &mgr = BstIdl::FDModelManager::getInstance();
        for (const auto &model : mgr.getModelList())
        {
            auto fdInterface = model->getInterfaceDeployment("org.genivi.commonapi.someip.deployment",
                                                             instance->getTarget()->getName());
            if (fdInterface != nullptr && fdInterface->getTarget() == instance->getTarget())
                return fdInterface;
        }
    }

    return nullptr;
}

std::string GeneralServiceGeneratorExtensions::getRecordDefineInLogic(const std::shared_ptr<BstIdl::FMethod> &fMethod)
{
    // record & simulate
    auto name = fMethod->getName();
    if (!isRecordAndSimulateInterface(std::dynamic_pointer_cast<BstIdl::FInterface>(fMethod->getContainer())))
        return std::string("");
    if (contains(record_simulate_methods, name) && name.compare("startRecord") == 0)
    {
        return "\n\tsetPath(_path);\n\t_reply();";
    }
    return std::string("");
}

std::string GeneralServiceGeneratorExtensions::getRecordDefineInStubImpl(
    const std::shared_ptr<BstIdl::FMethod> &fMethod)
{
    auto name = fMethod->getName();
    if (!isRecordAndSimulateInterface(std::dynamic_pointer_cast<BstIdl::FInterface>(fMethod->getContainer())))
        return std::string("");
    if (name.compare("startRecord") == 0)
    {
        return getStartRecordDefineInStubImpl(fMethod);
    }
    else if (name.compare("stopRecord") == 0)
    {
        return getStopRecordDefineInStubImpl(fMethod);
    }
    else if (name.compare("readRecord") == 0)
    {
        return getReadRecordDefineInStubImpl(fMethod);
    }
    else
    {
        std::cerr << "Error method " << fMethod->getFQN() << " named " << name << " to define record in StubImpl !"
                  << std::endl;
        return std::string("");
    }
}

std::string GeneralServiceGeneratorExtensions::getStartRecordDefineInStubImpl(
    const std::shared_ptr<BstIdl::FMethod> &fMethod)
{
    std::string define("");
    auto fInterface = std::dynamic_pointer_cast<BstIdl::FInterface>(fMethod->getContainer());
    if (fInterface == nullptr || getServer(fInterface).empty())
        return define;

    define += "\n\tstd::cout<<\"" + fMethod->getName() + " message\"<<std::endl;";
    define += "\n\tauto framework = AdvancedService::getInstance();";
    define += "\n\tauto recorder = std::static_pointer_cast<TRecorder>(framework->getTool(\"TRecorder\"));";
    define += "\n\tif (recorder)\n\t{";
    define += "\n\t\trecorder->stop();";
    define += "\n\t\trecorder->setFilename(_path);";
    define += "\n\t\trecorder->start();\n\t}";
    define += "\n\n\tm_record = true;";
    define += "\n\t_reply();";

    return define;
}

std::string GeneralServiceGeneratorExtensions::getStopRecordDefineInStubImpl(
    const std::shared_ptr<BstIdl::FMethod> &fMethod)
{
    std::string define("");
    auto fInterface = std::dynamic_pointer_cast<BstIdl::FInterface>(fMethod->getContainer());
    if (fInterface == nullptr || getServer(fInterface).empty())
        return define;

    define += "\n\tstd::cout<<\"" + fMethod->getName() + " message\"<<std::endl;";
    // reply client
    define += "\n\tm_record = false;";
    define += "\n\tauto framework = AdvancedService::getInstance();";
    define += "\n\tauto recorder = std::static_pointer_cast<TRecorder>(framework->getTool(\"TRecorder\"));";
    define += "\n\tif (recorder)\n\t{";
    define += "\n\t\trecorder->stop();\n\t}";
    define += "\n\t_reply();";

    return define;
}

std::string GeneralServiceGeneratorExtensions::getReadRecordDefineInStubImpl(
    const std::shared_ptr<BstIdl::FMethod> &fMethod)
{
    std::string define("");
    auto fInterface = std::dynamic_pointer_cast<BstIdl::FInterface>(fMethod->getContainer());
    if (fInterface == nullptr || getServer(fInterface).empty())
        return define;
    define += "\n\tauto framework = AdvancedService::getInstance();";
    define += "\n\tauto simulator = std::static_pointer_cast<TSimulator>(framework->getTool(\"TSimulator\"));";
    define += "\n\tif (simulator)\n\t{";
    define += "\n\t\tsimulator->stop();";
    define += "\n\t\tsimulator->setFilename(_path);";
    define += "\n\t\tsimulator->start();\n\t}";
    define += "\n\t_reply();";
    return define;
}

bool GeneralServiceGeneratorExtensions::isServerTypeInstance(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance) const
{
    auto type = m_accessor->getInstanceType(instance);
    return (type.empty() && geb_stub) || type == "server";
}

std::list<std::shared_ptr<BstIdl::FInterface>> GeneralServiceGeneratorExtensions::getServerTypeInterfacesIncludingBase()
    const
{
    std::list<std::shared_ptr<BstIdl::FInterface>> interfaces;
    for (const auto &ins : getServerInstances())
    {
        auto inf = std::dynamic_pointer_cast<BstIdl::FInterface>(ins->getTarget());
        if (addListItem(interfaces, inf))
            spliceBack(interfaces, BstIdl::FModelManager::getInstance().getBaseInterfaces(inf));
    }

    return interfaces;
}

std::list<std::shared_ptr<BstIdl::FInterface>> GeneralServiceGeneratorExtensions::getServerTypeInterfaces() const
{
    std::list<std::shared_ptr<BstIdl::FInterface>> interfaces;
    for (const auto &ins : getServerInstances())
    {
        auto inf = std::dynamic_pointer_cast<BstIdl::FInterface>(ins->getTarget());
        addListItem(interfaces, inf);
    }

    return interfaces;
}

bool GeneralServiceGeneratorExtensions::isClientTypeInstance(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance) const
{
    auto type = m_accessor->getInstanceType(instance);
    return type.empty() || type == "client";
}

std::list<std::shared_ptr<BstIdl::FInterface>> GeneralServiceGeneratorExtensions::getClientTypeInterfacesIncludingBase()
    const
{
    std::list<std::shared_ptr<BstIdl::FInterface>> interfaces;
    for (const auto &ins : getClientInstances())
    {
        auto inf = std::dynamic_pointer_cast<BstIdl::FInterface>(ins->getTarget());
        if (addListItem(interfaces, inf))
            spliceBack(interfaces, BstIdl::FModelManager::getInstance().getBaseInterfaces(inf));
    }

    return interfaces;
}
std::string GeneralServiceGeneratorExtensions::getHeaderPath(
    const std::shared_ptr<BstIdl::FTypeCollection> &fTypeCollection)
{
    return BstCommonAPI::FrancaGeneratorExtensions::getInstance().getHeaderPath(fTypeCollection);
}

void GeneralServiceGeneratorExtensions::generateRequiredTypeIncludes(
    const std::shared_ptr<BstIdl::FInterface> &fInterface, std::list<std::string> &generatedHeaders,
    std::list<std::string> &libraryHeaders)
{
    BstCommonAPI::FTypeGenerator::getInstance().generateRequiredTypeIncludes(fInterface, generatedHeaders,
                                                                             libraryHeaders, false);
}

std::string GeneralServiceGeneratorExtensions::getUserLogicName(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance) const
{
    return m_accessor->getUserLogicClassName(instance);
}

std::string GeneralServiceGeneratorExtensions::getUserLogicHeaderPath(
    const std::shared_ptr<BstIdl::FDExtensionElement> &instance) const
{
    return m_accessor->getUserLogicHeaderPath(instance);
}

bool GeneralServiceGeneratorExtensions::hasUserLogic(const std::shared_ptr<BstIdl::FDExtensionElement> &instance) const
{
    return !(getUserLogicName(instance).empty() || getUserLogicHeaderPath(instance).empty());
}

bool GeneralServiceGeneratorExtensions::isFireAndForgetMethod(const std::shared_ptr<BstIdl::FMethod> &method) const
{
    auto inf = std::dynamic_pointer_cast<BstIdl::FInterface>(method->getContainer());
    return method->isFireAndForget() && !BstIdl::FireAndForgetLimits::getInstance().isAsfInterface(inf);
}

// vsomeip config extensions
std::string GeneralServiceGeneratorExtensions::isReliable(const std::shared_ptr<BstIdl::FBroadcast> &_broadcast)
{
    auto someipAccessor =
        getSomeipAccessor(std::dynamic_pointer_cast<BstIdl::FTypeCollection>(_broadcast->getContainer()));
    auto value = someipAccessor->getSomeIpReliable(_broadcast);
    return value ? "true" : "false";
}

std::string GeneralServiceGeneratorExtensions::isReliable(const std::shared_ptr<BstIdl::FMethod> &_method)
{
    auto someipAccessor =
        getSomeipAccessor(std::dynamic_pointer_cast<BstIdl::FTypeCollection>(_method->getContainer()));
    auto value = someipAccessor->getSomeIpReliable(_method);
    return value ? "true" : "false";
}

std::string GeneralServiceGeneratorExtensions::isNotifierReliable(const std::shared_ptr<BstIdl::FAttribute> &_attribute)
{
    auto someipAccessor =
        getSomeipAccessor(std::dynamic_pointer_cast<BstIdl::FTypeCollection>(_attribute->getContainer()));
    bool value = someipAccessor->getSomeIpNotifierReliable(_attribute);
    return value ? "true" : "false";
}

std::string GeneralServiceGeneratorExtensions::getServerHostMessage(
    const std::shared_ptr<BstIdl::FDExtensionRoot> &_provider, const std::shared_ptr<ASFPropertyAccessor> &_accessor)
{
    if (!_provider || !_accessor)
        return std::string();
    else
        return std::string("\n\t\"unicast\": \"" + _accessor->getSomeIpServerHostUnicast(_provider) + "\"");
}

std::string GeneralServiceGeneratorExtensions::getClientHostMessage(
    const std::shared_ptr<BstIdl::FDExtensionRoot> &_provider, const std::shared_ptr<ASFPropertyAccessor> &_accessor)
{
    if (!_provider || !_accessor)
        return std::string();
    else
        return std::string("\n\t\"unicast\": \"" + _accessor->getSomeIpClientHostUnicast(_provider) + "\"");
}

std::string GeneralServiceGeneratorExtensions::getLogging(const std::shared_ptr<BstIdl::FDExtensionRoot> &_provider,
                                                          const std::shared_ptr<ASFPropertyAccessor> &_accessor)
{
    if (!_provider || !_accessor)
        return std::string();

    std::string logging("");
    auto level = _accessor->getSomeIpLoggingLevel(_provider);
    if (level.empty())
        return logging;
    std::list<std::string> content;
    content.emplace_back("\n\t\t\"level\" : \"" + level + "\"");
    bool isOK;
    auto consoleEnable =
        _accessor->getSomeIpLoggingViaConsole(_provider, isOK) ? std::string("true") : std::string("false");
    if (isOK)
        content.emplace_back("\n\t\t\"consolve\" : \"" + consoleEnable + "\"");
    auto logFileEnable =
        _accessor->getSomeIpCreateLogFile(_provider, isOK) ? std::string("true") : std::string("false");
    if (isOK)
    {
        auto logFileAbsPath = _accessor->getSomeIpLogFileAbsPath(_provider);
        content.emplace_back("\n\t\t\"file\" : { \"enable\" : \"" + logFileEnable + "\", \"path\" : \"" +
                             logFileAbsPath + "\" }");
    }
    auto diagnoseAndTraceEnable =
        _accessor->getSomeIpLoggingDLT(_provider, isOK) ? std::string("true") : std::string("false");
    if (isOK)
        content.emplace_back("\n\t\t\"dlt\" : \"" + diagnoseAndTraceEnable + "\"");
    auto versionCyclicLogEable =
        _accessor->getSomeIpVersionCyclicLogEable(_provider, isOK) ? std::string("true") : std::string("false");
    auto versionLogInterval = _accessor->getSomeIpVersionLogInterval(_provider);
    content.emplace_back("\n\t\t\"version\" : {\"enable\" : " + versionCyclicLogEable + ", \"interval\" : \"" +
                         std::to_string(versionLogInterval) + "\"}");
    auto memoryLogInterval = _accessor->getSomeIpMemoryLogInterval(_provider);
    auto statusLogInterval = _accessor->getSomeIpStatusLogInterval(_provider);
    if (memoryLogInterval > 0)
        content.emplace_back("\n\t\t\"memory_log_interval\" : \"" + std::to_string(memoryLogInterval) + "\"");
    if (statusLogInterval > 0)
        content.emplace_back("\n\t\t\"status_log_interval\" : \"" + std::to_string(statusLogInterval) + "\"");

    logging.append("\n\t\"logging\" : \n\t{" + join(content, ",") + "\n\t}");
    return logging;
}

std::string GeneralServiceGeneratorExtensions::getServiceDiscovery(
    const std::shared_ptr<BstIdl::FDExtensionRoot> &_provider, const std::shared_ptr<ASFPropertyAccessor> &_accessor)
{
    if (!_provider || !_accessor)
        return std::string();

    bool isOK;
    auto sd_enable = _accessor->getSomeIpServiceDiscoveryEnable(_provider, isOK);
    if (!isOK)
        return std::string();
    if (!sd_enable)
        return std::string("\n\t\"service-discovery\" : \n\t{\n\t\t\"enable\" : \"false\"\n\t}");
    auto multicast = _accessor->getSomeIpServiceDiscoveryMulticastAddress(_provider);
    auto port = _accessor->getSomeIpServiceDiscoveryPort(_provider);
    auto protocol = _accessor->getSomeIpServiceDiscoveryProtocol(_provider);
    auto initial_delay_min = _accessor->getSomeIpServiceDiscoveryInitialDelayMin(_provider);
    auto initial_delay_max = _accessor->getSomeIpServiceDiscoveryInitialDelayMax(_provider);
    auto repetitions_base_delay = _accessor->getSomeIpServiceDiscoveryRepetitionsBaseDelay(_provider);
    auto repetitions_max = _accessor->getSomeIpServiceDiscoveryRepetitionsMax(_provider);
    auto ttl = _accessor->getSomeIpServiceDiscoveryttl(_provider);
    auto cyclic_offer_delay = _accessor->getSomeIpServiceDiscoveryCyclicOfferDelay(_provider);
    auto request_response_delay = _accessor->getSomeIpServiceDiscoveryRequestResponseDelay(_provider);

    std::list<std::string> content;
    content.emplace_back("\n\t\t\"enable\" : \"false\"");
    content.emplace_back("\n\t\t\"multicast\" : \"" + multicast + "\"");
    content.emplace_back("\n\t\t\"port\" : \"" + std::to_string(port) + "\"");
    content.emplace_back("\n\t\t\"protocol\" : \"" + protocol + "\"");
    content.emplace_back("\n\t\t\"initial_delay_min\" : \"" + std::to_string(initial_delay_min) + "\"");
    content.emplace_back("\n\t\t\"initial_delay_max\" : \"" + std::to_string(initial_delay_max) + "\"");
    content.emplace_back("\n\t\t\"repetitions_base_delay\" : \"" + std::to_string(repetitions_base_delay) + "\"");
    content.emplace_back("\n\t\t\"repetitions_max\" : \"" + std::to_string(repetitions_max) + "\"");
    content.emplace_back("\n\t\t\"ttl\" : \"" + std::to_string(ttl) + "\"");
    content.emplace_back("\n\t\t\"cyclic_offer_delay\" : \"" + std::to_string(cyclic_offer_delay) + "\"");
    content.emplace_back("\n\t\t\"request_response_delay\" : \"" + std::to_string(request_response_delay) + "\"");
    std::string service_discovery("\n\t\"service-discovery\" : \n\t{" + join(content, ",") + "\n\t}");
    return service_discovery;
}

std::string GeneralServiceGeneratorExtensions::getApplications(
    const std::shared_ptr<BstIdl::FDExtensionRoot> &_provider, const std::shared_ptr<ASFPropertyAccessor> &_accessor)
{
    if (!_provider || !_accessor)
        return std::string();
    auto appList = getApplication(_provider, _accessor);
    std::string applications("\n\t\"applications\" : \n\t[" + join(appList, ",") + "\n\t]");
    return applications;
}

std::list<std::string> GeneralServiceGeneratorExtensions::getApplication(
    const std::shared_ptr<BstIdl::FDExtensionRoot> &_provider, const std::shared_ptr<ASFPropertyAccessor> &_accessor)
{
    std::list<std::string> apps;
    if (!_provider || !_accessor)
        return apps;
    auto names = _accessor->getSomeIpApplicationNames(_provider);
    auto ids = _accessor->getSomeIpApplicationIDs(_provider);
    if (ids.size() != names.size() || ids.empty())
        return apps;

    while (!names.empty() && !ids.empty())
    {
        auto name = names.front();
        auto id = ids.front();
        names.pop_front();
        ids.pop_front();
        std::string content("");
        content.append("\n\t\t\t\"name\" : \"" + name + "\",");
        content.append("\n\t\t\t\"id\" : \"" + id + "\"");
        apps.emplace_back("\n\t\t{" + content + "\n\t\t}");
    }
    return apps;
}
// vsomeip services
std::string GeneralServiceGeneratorExtensions::getServices(
    const std::shared_ptr<BstIdl::FDExtensionRoot> &_provider,
    const std::shared_ptr<BstIdl::FDExtensionRoot> &_someipProvider,
    const std::shared_ptr<ASFPropertyAccessor> &_accessor)
{
    if (!_provider || !_someipProvider || !_accessor)
        return std::string();
    auto serviceList = getService(_provider, _someipProvider, _accessor);
    std::string services("\n\t\"services\" : \n\t[" + join(serviceList, ",") + "\n\t]");
    return services;
}
std::list<std::string> GeneralServiceGeneratorExtensions::getService(
    const std::shared_ptr<BstIdl::FDExtensionRoot> &_provider,
    const std::shared_ptr<BstIdl::FDExtensionRoot> &_someipProvider,
    const std::shared_ptr<ASFPropertyAccessor> &_accessor)
{
    std::list<std::string> serviceList;
    if (!_provider || !_accessor)
        return serviceList;

    for (const auto &ins : _provider->getInstances())
    {
        if (!ins)
            continue;
        auto iter = std::find_if(_someipProvider->getInstances().cbegin(), _someipProvider->getInstances().cend(),
                                 [&ins](auto item) { return item->getTarget() == ins->getTarget(); });
        if (iter == _someipProvider->getInstances().cend())
            continue;
        auto someip_ins = *iter;
        auto fInterface = std::dynamic_pointer_cast<BstIdl::FInterface>(ins->getTarget());
        auto inf_accessor = getSomeipAccessor(fInterface);
        auto service = inf_accessor->getSomeIpServiceID(fInterface);
        auto events = getEvents(ins, inf_accessor);
        auto eventgroups = getEventGroups(ins, inf_accessor);

        auto ins_accessor = std::make_shared<BstCommonAPI::SomeipPropertyAccessor>(
            std::make_shared<BstIdl::FDeployedProvider>(_someipProvider));
        auto instance = ins_accessor->getSomeIpInstanceID(someip_ins);
        auto reliable = ins_accessor->getSomeIpReliableUnicastPort(someip_ins);
        auto unreliable = ins_accessor->getSomeIpUnreliableUnicastPort(someip_ins);

        std::list<std::string> content;
        content.emplace_back("\n\t\t\t\"service\" : \"" + std::to_string(service) + "\"");
        content.emplace_back("\n\t\t\t\"instance\" : \"" + std::to_string(instance) + "\"");
        content.emplace_back("\n\t\t\t\"reliable\" : \"" + std::to_string(reliable) + "\"");
        content.emplace_back("\n\t\t\t\"unreliable\" : \"" + std::to_string(unreliable) + "\"");
        if (!events.empty())
            content.emplace_back(events);
        if (!eventgroups.empty())
            content.emplace_back(eventgroups);
        serviceList.emplace_back("\n\t\t{" + join(content, ",") + "\n\t\t}");
    }

    return serviceList;
}
std::string GeneralServiceGeneratorExtensions::getEvents(
    const std::shared_ptr<BstIdl::FDExtensionElement> &_instance,
    const std::shared_ptr<BstCommonAPI::SomeipPropertyAccessor> &_accessor)
{
    std::string events("\n\t\t\t\"events\" : ");
    auto eventList = getEvent(_instance, _accessor);
    if (eventList.empty())
        return std::string();
    events.append("\n\t\t\t[" + join(eventList, ",") + "\n\t\t\t]");
    return events;
}
std::list<std::string> GeneralServiceGeneratorExtensions::getEvent(
    const std::shared_ptr<BstIdl::FDExtensionElement> &_instance,
    const std::shared_ptr<BstCommonAPI::SomeipPropertyAccessor> &_accessor)
{
    std::list<std::string> eventList;
    auto fInterface = std::dynamic_pointer_cast<BstIdl::FInterface>(_instance->getTarget());

    for (const auto &bc : fInterface->getBroadcasts())
    {
        auto event_id = getEventID(bc, _accessor);
        std::string event("\n\t\t\t\t{\n\t\t\t\t\t\"event\" : \"" + event_id + "\",");
        event.append("\n\t\t\t\t\t\"is_field\" : \"false\",");
        event.append("\n\t\t\t\t\t\"is_reliable\" : \"" + isReliable(bc) + "\"\n\t\t\t\t}");
        eventList.emplace_back(event);
    }
    for (const auto &attr : fInterface->getAttributes())
    {
        auto event_id = getNotifierID(attr, _accessor);
        std::string event("\n\t\t\t\t{\n\t\t\t\t\t\"event\" : \"" + event_id + "\",");
        event.append("\n\t\t\t\t\t\"is_field\" : \"true\",");
        event.append("\n\t\t\t\t\t\"is_reliable\" : \"" + isNotifierReliable(attr) + "\"\n\t\t\t\t}");
        eventList.emplace_back(event);
    }
    return eventList;
}
std::string GeneralServiceGeneratorExtensions::getEventGroups(
    const std::shared_ptr<BstIdl::FDExtensionElement> &_instance,
    const std::shared_ptr<BstCommonAPI::SomeipPropertyAccessor> &_accessor)
{
    std::string eventgroups("\n\t\t\t\"eventgroups\" : ");
    auto eventgroupList = getEventGroup(_instance, _accessor);
    if (eventgroupList.empty())
        return std::string();
    eventgroups.append("\n\t\t\t[" + join(eventgroupList, ",") + "\n\t\t\t]");
    return eventgroups;
}
std::list<std::string> GeneralServiceGeneratorExtensions::getEventGroup(
    const std::shared_ptr<BstIdl::FDExtensionElement> &_instance,
    const std::shared_ptr<BstCommonAPI::SomeipPropertyAccessor> &_accessor)
{
    std::list<std::string> eventgroups;
    auto fInterface = std::dynamic_pointer_cast<BstIdl::FInterface>(_instance->getTarget());

    for (const auto &bc : fInterface->getBroadcasts())
    {
        auto events_id = getEventID(bc, _accessor);
        for (const auto &id : getEventGroupsID(bc, _accessor))
        {
            std::string eventgroup("\n\t\t\t\t{\n\t\t\t\t\t\"eventgroup\" : \"" + id + "\",");
            eventgroup.append("\n\t\t\t\t\t\"events\" : [\"" + events_id + "\"]\n\t\t\t\t}");
            eventgroups.emplace_back(eventgroup);
        }
    }
    for (const auto &attr : fInterface->getAttributes())
    {
        auto events_id = getNotifierID(attr, _accessor);
        for (const auto &id : getNotifierEventGroupsID(attr, _accessor))
        {
            std::string eventgroup("\n\t\t\t\t{\n\t\t\t\t\t\"eventgroup\" : \"" + id + "\",");
            eventgroup.append("\n\t\t\t\t\t\"events\" : [\"" + events_id + "\"]\n\t\t\t\t}");
            eventgroups.emplace_back(eventgroup);
        }
    }

    return eventgroups;
}

std::string GeneralServiceGeneratorExtensions::getEventID(
    const std::shared_ptr<BstIdl::FBroadcast> &_broadcast,
    const std::shared_ptr<BstCommonAPI::SomeipPropertyAccessor> &_accessor)
{
    int value = _accessor->getSomeIpEventID(_broadcast);
    if (value != -1)
    {
        return std::to_string(value);
    }
    return "UNDEFINED_EVENT_ID";
}

std::string GeneralServiceGeneratorExtensions::getNotifierID(
    const std::shared_ptr<BstIdl::FAttribute> &_attribute,
    const std::shared_ptr<BstCommonAPI::SomeipPropertyAccessor> &_accessor)
{
    auto value = _accessor->getSomeIpNotifierID(_attribute);
    if (value != -1)
    {
        return std::to_string(value);
    }
    return "UNDEFINED_NOTIFIER_ID";
}

std::list<std::string> GeneralServiceGeneratorExtensions::getEventGroupsID(
    const std::shared_ptr<BstIdl::FBroadcast> &_broadcast,
    const std::shared_ptr<BstCommonAPI::SomeipPropertyAccessor> &_accessor)
{
    std::list<std::string> strs;
    std::list<int> value = _accessor->getSomeIpEventGroups(_broadcast);
    if (!value.empty())
    {
        for (const auto &it : value)
        {
            strs.emplace_back(std::to_string(it));
        }
    }
    return strs;
}

std::list<std::string> GeneralServiceGeneratorExtensions::getNotifierEventGroupsID(
    const std::shared_ptr<BstIdl::FAttribute> &_attribute,
    const std::shared_ptr<BstCommonAPI::SomeipPropertyAccessor> &_accessor)
{
    std::list<std::string> strs;
    std::list<int> value = _accessor->getSomeIpEventGroups(_attribute);
    if (!value.empty())
        for (const auto &it : value)
            strs.emplace_back(std::to_string(it));
    return strs;
}

} // namespace BstASF